package com.surprise.base.util;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import lombok.experimental.ExtensionMethod;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.surprise.base.entity.Address;

/**
 * AddressUtils.java
 * @author nick
 * @since 2015年9月13日
 */
@ExtensionMethod({ java.lang.Math.class })
public class AddressUtils {
	private final static double EARTH_RADIUS = 6378.137; // 千米

	private static double rad(double d) {
		return d * Math.PI / 180.0;
	}
	
	public static <T> void sortByDistance(List<T> fromCollection,
			final Function<? super T, Address> function, final Address toAdd) {
		Comparator<T> comparator = new Comparator<T>() {

			@Override
			public int compare(T o1, T o2) {
				Address a1 = function.apply(o1);
				Address a2 = function.apply(o2);

				long dis1 = distance(a1, toAdd);
				long dis2 = distance(a2, toAdd);
				if (dis1 > dis2) {
					return 1;
				}
				if (dis1 < dis2) {
					return -1;
				}
				return 0;
			}
		};
		Collections.sort(fromCollection, comparator);
	}
	
	public static long distance(Address o1, Address o2) {
		return distance(o1.getLatitude(), o1.getLongitude(), o2.getLatitude(), o2.getLongitude());
	}
	
	public static long distance(double lat1, double lng1, double lat2, double lng2) {
		double radLat1 = rad(lat1);
		double radLat2 = rad(lat2);
		double radLng1 = rad(lng1);
		double radLng2 = rad(lng2);
		double a = radLat1 - radLat2;
		double b = radLng1 - radLng2;
		double s = 2 * Math.asin(Math.sqrt(
					Math.pow(Math.sin(a / 2), 2)
					+ Math.cos(radLat1) * Math.cos(radLat2)
					* Math.pow(Math.sin(b / 2), 2)
					));
		s = s * EARTH_RADIUS * 1000; // 米
		long ret = Math.round(s);
		return ret;
	}
	
	public static void main(String[] args) {
		Address a1 = new Address(0, 0, "address1");
		Address a2 = new Address(10,10,"address2");
		Address a3 = new Address(3,3,"address3");
		List<Address> list = Lists.newArrayList(a1, a2, a3);
		sortByDistance(list, new Function<Address, Address>() {
			@Override
			public Address apply(Address input) {
				return input;
			}
		}, a1);
		System.out.println(list);
	}
}
